package com.presto.directo.utils

import android.Manifest
import android.annotation.SuppressLint
import android.content.Context
import android.content.pm.PackageManager
import android.location.*
import android.os.Bundle
import androidx.core.app.ActivityCompat
import com.presto.directo.entity.LocationInfo
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.core.ObservableEmitter
import java.util.concurrent.*

class LocationUtil {
    private var locationManager: LocationManager? = null
    private var location: Location? = null
    private var hasPermission = false
    private var netLocationListener: LocationListener? = null
    private var gpsLocationListener: LocationListener? = null

    @SuppressLint("MissingPermission")
    fun startLocation(context: Context): Observable<LocationInfo> {
        if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
            && ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED
        ) {
            hasPermission = false
            return Observable.just(LocationInfo("", "", "no_permission", hasPermission))
        }
        hasPermission = true
        locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
        val list = locationManager!!.getProviders(true)
        location = getLastKnownLocation(context)
        if (location == null) {
            val observables = arrayListOf<Observable<LocationInfo>>()
            if (list.contains(LocationManager.NETWORK_PROVIDER)) {
                observables.add(Observable.create {
                    locationManager!!.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1000, 0f, NetLocationListener(it))
                })
            }
            if (list.contains(LocationManager.GPS_PROVIDER)) {
                observables.add(Observable.create {
                    locationManager!!.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 0f, GpsLocationListener(it))
                })
            }
            observables.add(Observable.timer(5, TimeUnit.SECONDS)
                .applySchedulers()
                .flatMap {
                    Observable.just(LocationInfo(getLongitude(), getLatitude(), "timeout", hasPermission))
                })
            return Observable.ambArray(*observables.toTypedArray())
        } else {
            return Observable.just(LocationInfo(getLongitude(), getLatitude(), "last", hasPermission))
        }
    }

    private fun getLastKnownLocation(context: Context): Location? {
        val locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
        val providers = locationManager.allProviders
        var bestLocation: Location? = null
        for (provider in providers) {
            @SuppressLint("MissingPermission") val l = locationManager.getLastKnownLocation(provider) ?: continue
            if (bestLocation == null || l.accuracy < bestLocation.accuracy) {
                bestLocation = l
            }
        }
        return bestLocation
    }


    @SuppressLint("MissingPermission")
    fun stopLocation() {
        locationManager?.apply {
            netLocationListener?.let {
                removeUpdates(it)
            }
            gpsLocationListener?.let {
                removeUpdates(it)
            }
        }
    }

    inner class NetLocationListener(private val emitter: ObservableEmitter<LocationInfo>) : LocationListener {
        override fun onLocationChanged(location: Location) {
            setLocation(location)
            emitter.onNext(LocationInfo(getLongitude(), getLatitude(), "net", hasPermission))
            emitter.onComplete()
        }

        override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {}
        override fun onProviderEnabled(provider: String) {}
        override fun onProviderDisabled(provider: String) {}
    }

    inner class GpsLocationListener(private val emitter: ObservableEmitter<LocationInfo>) : LocationListener {
        override fun onLocationChanged(location: Location) {
            setLocation(location)
            emitter.onNext(LocationInfo(getLongitude(), getLatitude(), "gps", hasPermission))
            emitter.onComplete()
        }

        override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {}
        override fun onProviderEnabled(provider: String) {}
        override fun onProviderDisabled(provider: String) {}
    }

    private fun setLocation(location: Location) {
        this.location = location
    }


    private fun getLongitude(): String {
        return location?.longitude?.toString() ?: let {
            ""
        }
    }

    private fun getLatitude(): String {
        return location?.latitude?.toString() ?: let {
            ""
        }
    }

}
